package cn.fisok.pdman.command.impl;

import cn.fisok.pdman.command.Command;
import cn.fisok.pdman.command.ExecResult;
import cn.fisok.pdman.model.Module;
import cn.fisok.pdman.model.ModuleImage;
import cn.fisok.raw.kit.*;
import cn.fisok.raw.lang.MapObject;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.PictureRenderData;
import com.deepoove.poi.policy.BookmarkRenderPolicy;
import com.deepoove.poi.policy.HackLoopTableRenderPolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.List;
import java.util.Map;

public class GenDocxCommand extends AbstractDocCommand implements Command<ExecResult> {
    protected Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 填充生成图片对象
     * @param modules
     * @param imgExt
     * @throws IOException
     */
    private void fillModuleImages(List<Module> modules,String imgdir,String imgExt) throws IOException {
        if(!imgExt.startsWith(".")){
            imgExt = "."+imgExt;
        }
        if(imgdir.endsWith("/")){
            imgdir = imgdir.substring(0,imgdir.length()-1);
        }

        for(Module module : modules){

            String key = module.getKey();
            String label = module.getLabel();
            File imageFile = new File(imgdir+"/"+key+"-"+label+imgExt);    //默认情况下生成的文件名
            File imageSpareFile = new File(imgdir+"/"+key+imgExt);         //前端异常情况下，也会生成另一个文件名，作备用
            File effecFile = null;
            InputStream inputStream = null;
            if(imageFile.exists()){
                effecFile = imageFile;
            }else if(imageSpareFile.exists()){
                effecFile = imageSpareFile;
            }
            if(effecFile != null){

                //图片等比例缩放处理，防止图片被拉伸变形
                BufferedImage bufferedImage = ImageIO.read(effecFile);
                double width = bufferedImage.getWidth();
                double height = bufferedImage.getHeight();

                double fixWidth = 700;
                double fixHeight = 450;
                if(width>10 && height > 10){
                    double radix = fixWidth/width;
                    fixHeight = height * radix;
                }
                inputStream = FileKit.openInputStream(effecFile);
                PictureRenderData pictureRender = new PictureRenderData((int)fixWidth, (int)fixHeight, imgExt, inputStream);
                ModuleImage moduleImage = new ModuleImage();

                moduleImage.setInputStream(inputStream);
                moduleImage.setPath(effecFile.getPath());
                moduleImage.setImage(pictureRender);

                module.setGraphImages(ListKit.listOf(moduleImage));
            }
        }

    }

    public ExecResult exec(Map<String, String> params) {
        String pdmanfile = StringKit.nvl(params.get("pdmanfile"),""); //输入的PDMan文件
        String doctpl = StringKit.nvl(params.get("doctpl"),"");//文档模板文件
        String imgdir = StringKit.nvl(params.get("imgdir"),"");//图片文件存放目录
        String imgext = StringKit.nvl(params.get("imgext"),"");//图片文件后缀名
        String out = StringKit.nvl(params.get("out"),"");     //输出文件名
        if (pdmanfile.isEmpty()) throw new RuntimeException("参数[pdmanfile]缺失");
        if (doctpl.isEmpty()) throw new RuntimeException("参数[doctpl]缺失");
        if (imgdir.isEmpty()) throw new RuntimeException("参数[imgdir]缺失");
        if (imgext.isEmpty()) throw new RuntimeException("参数[imgext]缺失");
        if (out.isEmpty()) throw new RuntimeException("参数[out]缺失");

        ExecResult ret = new ExecResult();

        File tplFile = new File(doctpl);
        File outFile = new File(out);
        List<Module> modules = null;
        try (
                InputStream tplIn = new FileInputStream(tplFile);
                OutputStream resultOut = new FileOutputStream(outFile);
                ){
            MapObject fileMapObject = parseFile(pdmanfile);
            modules = parseModules(fileMapObject);

            fillModuleImages(modules,imgdir,imgext);

            Map<String,Object> dataModel = MapKit.mapOf("modules",modules);

            HackLoopTableRenderPolicy policy = new HackLoopTableRenderPolicy();
            Configure config = Configure.newBuilder()
                    .bind("entities", policy)
                    .bind("fields", policy)
//                    .bind("image", new PictureRenderPolicy())
                    .addPlugin('>', new BookmarkRenderPolicy())
                    .build();

            XWPFTemplate template = XWPFTemplate.compile(tplIn,config).render(dataModel);
            template.write(resultOut);
            resultOut.flush();
            resultOut.close();
            template.close();

            ret.setStatus(ExecResult.SUCCESS);
            ret.setBody(out);
        } catch (Exception ex) {
            logger.warn("", ex);
            ret.setStatus(ExecResult.FAILED);
            ret.setBody(ex.getMessage());
        } finally {
            //把之前打开的图片输入流关闭掉
            if(modules != null && modules.size()>0){
                modules.forEach(module -> {
                    List<ModuleImage> moduleImages = module.getGraphImages();
                    if(moduleImages != null && moduleImages.size()>0){
                        moduleImages.forEach(moduleImage -> {
                            IOKit.close(moduleImage.getInputStream());
                        });
                    }
                });
            }
        }
        return ret;
    }



    private void showUsage() {
        logger.info(
                "arg-0: json file path" + System.lineSeparator() +
                        "arg-1: word document template path" + System.lineSeparator() +
                        "arg-2: image directory" + System.lineSeparator() +
                        "arg-3: image extension(.png|.jpeg|...)" + System.lineSeparator() +
                        "arg-4: output file name(*.doc|*.docx|*.pdf|*.html)"
        );
    }

    private static void validateFileFormat(String ext) {
        if (".doc".equals(ext) || ".docx".equals(ext) || ".pdf".equals(ext) || ".html".equals(ext))
            return;
        throw new IllegalArgumentException("can only export *.doc|*.docx|*.pdf|*.html file");
    }
}
